Private "Application Level" Dictionary Support
----------------------------------------------
TurboForth currently does not support vocabularies, as found in many other Forth systems. If one is loading single applications into memory this is rarely an issue. However, if one wishes to load multiple applications into memory, or applications, and say, a shared library (that the applications themselves utilise) there is a potential for name collisions, since all definitions, of all types share the same dictionary.

The following provides a solution to the issue. The following code (see bottom of article) introduces the concept of "applications". All words within an application are private. They cannot be seen by words that are outside of the application. The developer of an application can 'expose' certain words to the outside world, effectively making those words global.

This is useful:

To hide the low-level implementation details of applications. When an application is loaded into memory, typing WORDS can lead to screen-fuls of words being displayed, and it is not clear which words are internal to the application, and which words are the "public interface" side of the application. Applications solve that problem. They allow the internal workings of an application to be hidden from WORDS, and indeed the dictionary overall, such that only the words that the application developer has explicitly chosen to expose are visible. This of course also vastly reduces the risk of name collisions.
    

Example of usage:
-----------------
: john dup ;
application: fred
    : test1 ( -- n ) 123 ; entry-point
    : test2 ( -- n ) 456 ;
    : test3 ( -- n ) 789 john ;
    : start ( -- a b c ) test1 test2 test3 ; entry-point
    expose test3
end-application

In the above example, test1, test2, and test3 are not visible to words outside of the application called fred.

Entry Points
------------
Note that the word start has been marked as the entry-point. This is useful where it is desirable to wrap an entire application up and expose a single word as the entry-point to the application. When a word is marked as the entry-point the word is linked to name of the application, such that referencing the name of the application causes the nominated entry-point to execute. Therefore, in the above example, fred inherits the stack signature of start, and executing fred shall cause start to be executed. In turn, start subsequently executes the private words test1, test2, and test3.

Only one word should be defined as the entry-point. Defining more than one word as an entry-point shall simply cause the last word so marked to become the entry-point, and the previously so marked words to be public.

Making Words Public (Defining the Public Interface)
---------------------------------------------------
It is also possible to expose other words in the application to the outside world. This is very useful for library development; it allows the 'public facing' words (the interface) to be exposed to the outside world, and allows the inner words (the implementation) to be hidden. Use the EXPOSE keyword to expose a word, as shown in the following example:

application: string_lib
    256 constant stack_size
    variable stack_pointer
    create string_stack stack_size allot    \ reserve stack space
    string_stack stack_pointer !            \ init stack pointer
    
    : $depth ( -- depth ) ... ... ... ... ... ;
    : 2strings ( -- ) $depth 2 < abort" Need two strings!" ;
    
    : do_setup ( -- ) ... ... ... ... ; entry-point
    : dup$ ( -- ) 2strings? ... ... ... ... ;
    : swap$ ( -- ) 2strings? .. .. ... ... ;
    
    \ the following words shall be made public
    expose dup$
    expose swap$
end-application

In the above example, do_setup is marked as the entry-point of the application/library. Note that marking a word as the entry-point makes it public. The word can now be accessed directly by its name, or by the name of the application, which in this example is called string_lib.

In addition, the words dup$ and swap$ are exposed, and are therefore public.

Note that stack_size, stack_pointer, string_stack, $depth and 2strings? are not exposed, and are therefore private to the application; they may not be referenced outside of the application in which they are defined.


Implementation Code
-------------------
The following code implements the functionality described above:

new


variable lastLink
variable entryPoint
variable appLink

: noEntry ( -- ) 
    true abort" No entry point defined." ;

: application: ( "name" -- )
    create  latest @ appLink !
    ['] noEntry entryPoint !
    latest @ lastLink !
    ['] noEntry , does> @ execute ;

: expose ( "name" -- )
    >in @  lastLink @ ' ?dup if 
        >link dup >r !
        r> lastLink !
    else
        cr drop 
        >in ! bl word type 
        true abort" : Word not found. Cannot expose."
    then drop ;

: entry-point ( -- )
    latest @ >cfa entryPoint ! ;

: end-application ( -- )
    entryPoint @ ['] noEntry = if
        noEntry
    else
        entryPoint @ appLink @ >cfa >body !
        lastLink @ latest !
    then ;


\ test code:
application: fred
    : test1 ( -- 1 ) 1 ;
    : test2 ( -- 2 ) 2 ;
    : test3 ( -- 3 ) 3 ;
    : CanYouSeeMe ." Hello!!" cr ;
    : test test1 test2 test3 ; entry-point
    : ImHiding ." Hi!" cr ; entry-point
    : WhatAboutMe ." Boo!" cr ;
    
    expose CanYouSeeMe
    expose WhatAboutMe
end-application

: bouncer ." boing!" cr ;


